﻿using System;
using System.Activities;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YasharEl.Infrastructure.WorkflowModel;
using YasharEl.Infrastructure.ObjectFactory;
using YasharEl.Infrastructure.ProcessEngine.DomainModel.WorkflowManagement;
using YasharEl.Infrastructure.ResourcesManagement;
using YasharEl.Infrastructure.WorkflowModel.Configuration;

namespace YasharEl.Infrastructure.ProcessEngine.DomainModel.Implementation.WorkflowManagement
{
    public class DefaultWorkflowExecutionManager : IWorkflowExecutionManager
    {
        #region Fields

        private readonly IWorkflowActivityFinder workflowActivityFinder;
        private readonly IDependencyResolver resolver;

        #endregion

        #region Constructors

        public DefaultWorkflowExecutionManager(IWorkflowActivityFinder workflowActivityFinder, IDependencyResolver resolver)
        {
            Contract.Requires<ArgumentNullException>(workflowActivityFinder != null, "workflowActivityFinder could not be null.");
            Contract.Requires<ArgumentNullException>(resolver != null, "resolver could not be null.");

            this.workflowActivityFinder = workflowActivityFinder;
            this.resolver = resolver;
        }

        #endregion

        #region IWorkflowExecutionManager Implementations

        public WorkflowApplication StartWorkflowSuspended(string workflowXaml, Dictionary<string, object> inputs, WorkflowIdentity workflowIdentity)
        {
            IDictionary<string,DynamicActivityProperty> definedProperties = new Dictionary<string,DynamicActivityProperty>();
            Activity activity = workflowActivityFinder.FindWorkflowProgram(workflowXaml, out definedProperties);
            if (activity == null)
            {
                throw new CouldNotFindWorkflowProgramException(resolver.Resolve<IResourceManager>(),
                    workflowXaml);
            }

            //Create a new instance from this definition
            WorkflowApplication workflowInstance = null;

            if (inputs != null && inputs.Count > 0)
            {
                Dictionary<string, object> workflowInputs = new Dictionary<string, object>();

                if (definedProperties != null && definedProperties.Count > 0)
                {
                    // Try to recognize input arguments...
                    foreach (var input in inputs)
                    {
                        DynamicActivityProperty property = definedProperties.Values.SingleOrDefault((d) => d.Name == input.Key);
                        if (property != null)
                        {
                            workflowInputs.Add(input.Key, input.Value);
                        }
                    }
                }
                workflowInstance = new WorkflowApplication(activity, workflowInputs, workflowIdentity);
            }
            else
            {
                workflowInstance = new WorkflowApplication(activity, workflowIdentity);
            }

            workflowInstance
                .SetupDefaults(resolver)
                .SetupInstanceStore(resolver);

            return workflowInstance;
        }

        public WorkflowApplication RunWorkflow(WorkflowApplication workflowApplication)
        {
            workflowApplication.Run();

            return workflowApplication;
        }

        public WorkflowApplication RetriveWorkflowInstance(string workflowXaml, Guid workflowInstanceId, WorkflowIdentity workflowIdentity)
        {
            IDictionary<string, DynamicActivityProperty> definedProperties = new Dictionary<string, DynamicActivityProperty>();
            Activity activity = workflowActivityFinder.FindWorkflowProgram(workflowXaml, out definedProperties);
            if (activity == null)
            {
                throw new CouldNotFindWorkflowProgramException(resolver.Resolve<IResourceManager>(),
                    workflowXaml);
            }

            WorkflowApplication workflowInstance = null;

            // TODO : Load workflow inputs and pass it to workflow application here
            workflowInstance = new WorkflowApplication(activity, workflowIdentity);

            workflowInstance
                .SetupDefaults(resolver)
                .SetupInstanceStore(resolver);

            workflowInstance.Load(workflowInstanceId);

            return workflowInstance;
        }

        #endregion
    }
}
